package com.tzy.for10evalue.designpattern.singleton;

/**
 * @author tzy
 * @date 2022/6/14 11:37
 */
public class Singleton1 {
    private volatile static Singleton1 instance;

    private Singleton1() {
    }

    public static Singleton1 getInstance() {
        if (instance == null) {
            synchronized (Singleton1.class) {
                if (instance == null) {
                    instance = new Singleton1();//erro
                }
            }
        }
        return instance;
    }

   /* 1.为什么双重检验 (即为什么使用了两个if语句)
    外层判断：完成实例化后，之后的线程就不需要再执行synchronized等待，提高效率。
    内层判断：防止多次实例化。
    2.为什么加双锁（即为什么同时使用了synchronized关键字和volatile关键字）
    如果不使用volatile关键字，隐患来自于上述代码中注释了 erro 的一行，这行代码大致有以下三个步骤：
    在堆中开辟对象所需空间，分配地址
    根据类加载的初始化顺序进行初始化
    将内存地址返回给栈中的引用变量
    由于 Java 内存模型允许“无序写入”，有些编译器因为性能原因，可能会把上述步骤中的 2 和 3 进行重排序，顺序就成了
    3.JDK版本为什么要大于1.5
    volatile关键字的屏蔽指令重排的语义在JDK1.5中才被完全修复。
    JDK5 以及后续版本扩展了volatile语义，不再允许volatile写操作与其前面的读写操作重排序，也不允许volatile读操作与其后面的读写操作重排序。*/
}
